using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Xml;
using Common.Utilities;
using Common.Utilities.Dispatcher;

namespace Workflows.Components.ETL
{
    [Serializable]
    public class SaveToDbInstruction:InstructionBase
    {
        #region props
        private TableUpdateAction _UpdateAction;

        public TableUpdateAction UpdateAction
        {
            get { return _UpdateAction; }
            set { _UpdateAction = value; }
        }

        private TableDataFeedType _TableFeedType;

        public TableDataFeedType TableFeedType
        {
            get { return _TableFeedType; }
            set { _TableFeedType = value; }
        }

        private string _SrcObjTypeName;

        public string SrcObjectTypeName
        {
            get { return _SrcObjTypeName; }
            set { _SrcObjTypeName = value; }
        }

        private List<TableColumn> _SrcTableCols;

        public List<TableColumn> SourceTableColumns
        {
            get { return _SrcTableCols; }
            set { _SrcTableCols = value; }
        }
	
        private bool _EnableIdentityInsert;
        public bool EnableIdentityInsert
        {
            get
            {
                return this._EnableIdentityInsert;
            }
            set
            {
                this._EnableIdentityInsert = value;
            }
        }

        private Dictionary<string, string> _FieldMappings;

        public Dictionary<string, string> FieldMappings
        {
            get { return _FieldMappings; }
            set { _FieldMappings = value; }
        }

        private string _PkField;

        public string PkField
        {
            get { return _PkField; }
            set { _PkField = value; }
        }

        private string _ConnectionString;

        public string ConnectionString
        {
            get { return _ConnectionString; }
            set { _ConnectionString = value; }
        }

        private string _TableName;

        public string TableName
        {
            get { return _TableName; }
            set { _TableName = value; }
        }
        #endregion

        public SaveToDbInstruction()
            : base(Guid.Empty, Guid.Empty)
        {
            this._UpdateAction = TableUpdateAction.Insert;
            this._TableFeedType = TableDataFeedType.ObjectListInMemory;
            this._SrcObjTypeName = string.Empty;
            this._FieldMappings = new Dictionary<string, string>();
            this._PkField = "[ID]";
            this._ConnectionString = "server=localhost;database=enumeration;integrated security=SSPI";
            this._TableName = "[table]";
            this._EnableIdentityInsert = false;
        }

        public SaveToDbInstruction(Guid componentID, Guid jobTicketID, 
            TableUpdateAction updateAction, TableDataFeedType tableFeedType,
            string srcObjTypeName, Dictionary<string,string> fieldMappings, string pkField,
            string connStr, string tblName, bool enableIdentityInsert) : base(componentID, jobTicketID)
        {
            this._UpdateAction = updateAction;
            this._TableFeedType = tableFeedType;
            this._SrcObjTypeName = srcObjTypeName;
            this._FieldMappings = fieldMappings;
            this._PkField = pkField;
            this._ConnectionString = connStr;
            this._TableName = tblName;
            this._EnableIdentityInsert = enableIdentityInsert;
        }

        public override XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode)
        {
            XmlNode saveToDbNode = XmlDataUtil.AddElement(ref xDoc, parentNode, "Instruction");
            XmlDataUtil.UpdateAttribute(ref xDoc, saveToDbNode, "Type", this.GetType().FullName);
            XmlDataUtil.UpdateAttribute(ref xDoc, saveToDbNode, "ComponentID", this.OwnerComponentID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, saveToDbNode, "WorkerID", this.OwnerWorkerInstanceID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, saveToDbNode, "SubmitTime", this.SubmitTime.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, saveToDbNode, "StartTime", this.StartTime.ToString());

            XmlDataUtil.UpdateAttribute(ref xDoc, saveToDbNode, "UpdateAction", ((int) this.UpdateAction).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, saveToDbNode, "TableFeedType", ((int)this.TableFeedType).ToString());
            if (this.TableFeedType == TableDataFeedType.ObjectListInMemory)
            {
                XmlDataUtil.UpdateAttribute(ref xDoc, saveToDbNode, "SrcObjectTypeName", this.SrcObjectTypeName);
            }
            else
            {
                if (this.SourceTableColumns != null && this.SourceTableColumns.Count > 0)
                {
                    XmlNode srcSchemaNode = XmlDataUtil.AddElement(ref xDoc, saveToDbNode, "SourceTableColumns");
                    foreach (TableColumn col in this.SourceTableColumns)
                    {
                        XmlNode tblColNode = XmlDataUtil.AddElement(ref xDoc, srcSchemaNode, "TableColumn");
                        XmlDataUtil.UpdateAttribute(ref xDoc, tblColNode, "ColumnName", col.ColumnName);
                        XmlDataUtil.UpdateAttribute(ref xDoc, tblColNode, "Ordinal", col.Ordinal.ToString());
                        XmlDataUtil.UpdateAttribute(ref xDoc, tblColNode, "DbType", ((int) col.DbType).ToString());
                        XmlDataUtil.UpdateAttribute(ref xDoc, tblColNode, "Size", col.Size.ToString());
                        XmlDataUtil.UpdateAttribute(ref xDoc, tblColNode, "IsPK", col.IsPK.ToString());
                        XmlDataUtil.UpdateAttribute(ref xDoc, tblColNode, "IsIdentity", col.IsIdentity.ToString());
                        XmlDataUtil.UpdateAttribute(ref xDoc, tblColNode, "AllowNull", col.AllowNull.ToString());
                    }
                }
            }
            XmlDataUtil.UpdateAttribute(ref xDoc, saveToDbNode, "ConnectionString", this.ConnectionString);
            XmlDataUtil.UpdateAttribute(ref xDoc, saveToDbNode, "TableName", this.TableName);
            XmlDataUtil.UpdateAttribute(ref xDoc, saveToDbNode, "PkField", this.PkField);
            XmlDataUtil.UpdateAttribute(ref xDoc, saveToDbNode, "EnableIdentityInsert", this.EnableIdentityInsert.ToString());
            if(this.FieldMappings !=null && this.FieldMappings.Count>0)
            {
                XmlNode fieldMappingNodes = XmlDataUtil.AddElement(ref xDoc, saveToDbNode, "FieldMappings");
                foreach (string srcField in this.FieldMappings.Keys)
                {
                    XmlNode fieldMappingNode = XmlDataUtil.AddElement(ref xDoc, fieldMappingNodes, "FieldMapping");
                    XmlDataUtil.UpdateAttribute(ref xDoc, fieldMappingNode, "SrcField", srcField);
                    XmlDataUtil.UpdateAttribute(ref xDoc, fieldMappingNode, "TargetField", this.FieldMappings[srcField]);
                }
            }

            return saveToDbNode;
        }

        public override InstructionBase Instantiate(XmlNode xNode)
        {
            if (xNode.Attributes.GetNamedItem("Type").Value == this.GetType().FullName)
            {
                SaveToDbInstruction instruction = new SaveToDbInstruction();
                instruction.OwnerComponentID = new Guid(xNode.Attributes.GetNamedItem("ComponentID").Value);
                instruction.OwnerWorkerInstanceID = new Guid(xNode.Attributes.GetNamedItem("WorkerID").Value);
                instruction.SubmitTime = DateTime.Parse(xNode.Attributes.GetNamedItem("SubmitTime").Value);
                instruction.StartTime = DateTime.Parse(xNode.Attributes.GetNamedItem("StartTime").Value);

                instruction.UpdateAction =
                    (TableUpdateAction) int.Parse(xNode.Attributes.GetNamedItem("UpdateAction").Value);
                instruction.TableFeedType = (TableDataFeedType)int.Parse(xNode.Attributes.GetNamedItem("TableFeedType").Value);

                if (instruction.TableFeedType == TableDataFeedType.ObjectListInMemory)
                {
                    instruction.SrcObjectTypeName = xNode.Attributes.GetNamedItem("SrcObjectTypeName").Value;
                }
                else
                {
                    instruction.SourceTableColumns = new List<TableColumn>();
                    XmlNodeList colNodes = xNode.SelectNodes("SourceTableColumns/TableColumn");
                    if (colNodes != null && colNodes.Count > 0)
                    {
                        foreach (XmlNode colNode in colNodes)
                        {
                            TableColumn col = new TableColumn();
                            col.ColumnName = colNode.Attributes.GetNamedItem("ColumnName").Value;
                            col.Ordinal = int.Parse(colNode.Attributes.GetNamedItem("Ordinal").Value);
                            col.DbType = (SqlDbType) int.Parse(colNode.Attributes.GetNamedItem("DbType").Value);
                            col.Size = int.Parse(colNode.Attributes.GetNamedItem("Size").Value);
                            col.IsPK = bool.Parse(colNode.Attributes.GetNamedItem("IsPK").Value);
                            col.IsIdentity = bool.Parse(colNode.Attributes.GetNamedItem("IsIdentity").Value);
                            col.AllowNull = bool.Parse(colNode.Attributes.GetNamedItem("AllowNull").Value);
                            instruction.SourceTableColumns.Add(col);
                        }
                    }
                }

                instruction.PkField = xNode.Attributes.GetNamedItem("PkField").Value;
                instruction.ConnectionString = xNode.Attributes.GetNamedItem("ConnectionString").Value;
                instruction.TableName = xNode.Attributes.GetNamedItem("TableName").Value;
                instruction.EnableIdentityInsert = bool.Parse(xNode.Attributes.GetNamedItem("EnableIdentityInsert").Value);

                instruction.FieldMappings = null;
                XmlNodeList fieldMappingNodes = xNode.SelectNodes("FieldMappings/FieldMapping");
                if (fieldMappingNodes != null && fieldMappingNodes.Count > 0)
                {
                    instruction.FieldMappings = new Dictionary<string, string>();
                    foreach (XmlNode fieldMappingNode in fieldMappingNodes)
                    {
                        string srcField = fieldMappingNode.Attributes.GetNamedItem("SrcField").Value;
                        string tgtField = fieldMappingNode.Attributes.GetNamedItem("TgtField").Value;
                        instruction.FieldMappings.Add(srcField, tgtField);
                    }
                }
                
                return instruction;
            }
            else
                throw new Exception("Unable to instantiate component: invalid type specified in xml node");
        }
    }
}
